package com.innoking.docsys.workflow.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.innoking.docsys.utils.JsonToOtherUtil;
import com.innoking.docsys.utils.OtherPojo;
import com.innoking.docsys.utils.ResultObjVO;
import com.innoking.docsys.utils.ResultUtil;
import com.innoking.docsys.workflow.componet.WorkflowProcessDefinitionComponent;
import com.innoking.docsys.workflow.dto.UpmsActDefine;
import com.innoking.docsys.workflow.example.UpmsActDefineClusterExample;
import com.innoking.docsys.workflow.service.WorkflowDefineService;
import com.innoking.docsys.workflow.service.WorkflowDeployService;
import com.innoking.docsys.workflow.utils.WorkflowPageUtil;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.zip.ZipInputStream;

/**
 * 描述:
 *
 * @author zyp
 * @description 工作流部署service实现类
 * @create 2019-09-06 14:13
 */
@Service
public class WorkflowDeployServiceImpl implements WorkflowDeployService{

    Logger logger= LoggerFactory.getLogger(WorkflowDeployServiceImpl.class);

    @Autowired
    protected RepositoryService repositoryService;

    @Autowired
    protected RuntimeService runtimeService;

    @Autowired
    protected TaskService taskService;

    @Autowired
    ProcessEngineFactoryBean processEngine;

    @Autowired
    ProcessEngineConfiguration processEngineConfiguration;

    @Autowired
    public WorkflowDefineService workflowDefineService;

    @Autowired
    private WorkflowProcessDefinitionComponent workflowProcessDefinitionComponent;

    /**
     * @author:zyp
     * @description 获取工作流部署
     * @date: 2019/9/9 11:09
     * @return 
     */
    @Override
    public ResultObjVO getActDeploy(String data) {
        OtherPojo ob = JsonToOtherUtil.rtOtherPojo(data, new String());
        int offset = 1;
        int limit = 1;
        String search = "";
        Map<String, Object> result = new HashMap<String , Object>();
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery().list();
        for ( ProcessDefinition processDefinition : processDefinitionList) {
            Map<String, Object> paremeterMap = new HashMap<String , Object>();
            paremeterMap.put("id",processDefinition.getId());
            paremeterMap.put("deploymentId",processDefinition.getDeploymentId());
            paremeterMap.put("name",processDefinition.getName());
            paremeterMap.put("key",processDefinition.getKey());
            paremeterMap.put("version",processDefinition.getVersion());
            paremeterMap.put("resourceName",processDefinition.getResourceName());
            paremeterMap.put("diagramResourceName",processDefinition.getDiagramResourceName());
            paremeterMap.put("suspended",processDefinition.isSuspended());
            String deploymentId = processDefinition.getDeploymentId();
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            paremeterMap.put("deploymentTime",deployment.getDeploymentTime());
            //获取当前部署的流程应用的情况
            List<UpmsActDefine> upmsActDefines = workflowDefineService.selectDefineByKey(processDefinition.getKey());
            StringBuilder sb = new StringBuilder();
            for(UpmsActDefine upmsActDefine : upmsActDefines){
                //需要获取字典表的code内容进行名字获取
                sb.append(upmsActDefine.getAdCode());
            }
            paremeterMap.put("actDefineName",sb.toString());
            list.add(paremeterMap);
        }
        List<Map<String, Object>> finalList = WorkflowPageUtil.pagingActDeploy(list,offset,limit,search);
        result.put("rows",finalList);
        result.put("total",list.size());
        return ResultUtil.success(result);
    }

    /**
     * @author:zyp
     * @description 通过部署id  下载资源
     * @date: 2019/9/9 11:21
     * @return 
     */
    @Override
    public void loadByDeployment(String processDefinitionId,String resourceType,HttpServletResponse response) {
        try {
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
            String resourceName = "";
            if (resourceType.equals("image")) {
                resourceName = processDefinition.getDiagramResourceName();
            } else if (resourceType.equals("xml")) {
                resourceName = processDefinition.getResourceName();
            }
            InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
            byte[] b = new byte[1024];
            int len = -1;
            while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
                response.getOutputStream().write(b, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @author:zyp
     * @description 删除部署 级联删除
     * @date: 2019/9/9 11:42
     * @return
     */
    @Override
    public ResultObjVO deleteDeploy(List<String> deploymentIds) {
        for (String id : deploymentIds) {
            if (StringUtils.isBlank(id)) {
                continue;
            }
            repositoryService.deleteDeployment(id, true);
        }
        return ResultUtil.success("删除成功");
    }

    /**
     * @author:zyp
     * @description 根据部署id转换为model
     * @date: 2019/9/9 11:49
     * @return 
     */
    @Override
    public ResultObjVO convertToModel(List<String> deploymentIds) {
        for (String id : deploymentIds) {
            if (StringUtils.isBlank(id)) {
                continue;
            }
            try{
                ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                        .processDefinitionId(id).singleResult();
                InputStream bpmnStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
                        processDefinition.getResourceName());
                XMLInputFactory xif = XMLInputFactory.newInstance();
                InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
                XMLStreamReader xtr = xif.createXMLStreamReader(in);
                BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);

                BpmnJsonConverter converter = new BpmnJsonConverter();
                ObjectNode modelNode = converter.convertToJson(bpmnModel);
                Model modelData = repositoryService.newModel();
                modelData.setKey(processDefinition.getKey());
                modelData.setName(processDefinition.getResourceName());
                modelData.setCategory(processDefinition.getDeploymentId());

                ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
                modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName());
                modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
                modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
                modelData.setMetaInfo(modelObjectNode.toString());
                repositoryService.saveModel(modelData);
                repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
            }catch (UnsupportedEncodingException ueE){
                ueE.printStackTrace();
            }catch(XMLStreamException xmlE){
                xmlE.printStackTrace();
            }
        }
        return ResultUtil.success("转换成功");
    }

    /**
     * @author:zyp
     * @description 根据文件部署项目 并且定义其流程
     * @date: 2019/9/9 12:00
     * @return 
     */
    @Override
    public ResultObjVO deployByFile(MultipartFile file, String defineCode) {
        String fileName = file.getOriginalFilename();
        try {
            InputStream fileInputStream = file.getInputStream();
            Deployment deployment = null;
            String extension = FilenameUtils.getExtension(fileName);
            if (extension.equals("zip") || extension.equals("bar")) {
                ZipInputStream zip = new ZipInputStream(fileInputStream);
                deployment = repositoryService.createDeployment().addZipInputStream(zip).deploy();
            } else {
                deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
            }
            List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
            if(list!=null&&list.size()>0){
                String key = list.get(0).getKey();
                //默认更换定义
                workflowDefineService.updateStatusByAdCode(key);
                //先查看当前定义中是否有当前的定义code 与 模型key数据
                boolean existByCodeKey = workflowDefineService.isExistByCodeKey(key, defineCode);
                //存在 则为更新
                if(existByCodeKey){
                    UpmsActDefine actDefine = new UpmsActDefine();
                    actDefine.setAdStatus(1L);
                    UpmsActDefineClusterExample upmsActDefineClusterExample = new UpmsActDefineClusterExample();
                    UpmsActDefineClusterExample.Criteria actDefineExampleCriteria = upmsActDefineClusterExample.createCriteria();
                    actDefineExampleCriteria.andAdCodeEqualTo(defineCode);
                    actDefineExampleCriteria.andAdKeyEqualTo(key);
                    workflowDefineService.updateWorkflowDefine(actDefine,upmsActDefineClusterExample);
                }else{
                    UpmsActDefine actDefine = new UpmsActDefine();
                    actDefine.setAdKey(key);
                    actDefine.setAdStatus(1L);
                    actDefine.setCreateTime(new Date());
                    actDefine.setAdCode(defineCode);
                    workflowDefineService.insert(actDefine);
                }
            }
        } catch (Exception e) {
            logger.error("error on deploy process, because of file input stream", e);
            return ResultUtil.error();
        }
        return ResultUtil.success("部署成功");
    }

    /**
     * @author:zyp
     * @description 修改部署状态
     * @date: 2019/9/9 16:14
     * @return 
     */
    @Override
    public ResultObjVO updateState(String state, String deploymentId) {
        if ("active".equals(state)) {
            repositoryService.activateProcessDefinitionById(deploymentId, true, null);
            return ResultUtil.success("挂起成功");
        } else {
            repositoryService.suspendProcessDefinitionById(deploymentId, true, null);
            return ResultUtil.success("激活成功");
        }
    }
}